
/*
 * Copyright (C) 2008-2009 Archie L. Cobbs. All rights reserved.
 *
 * $Id: XMLSimpleFieldSwitch.java 377 2010-03-11 20:50:18Z archie.cobbs $
 */

package org.dellroad.sidekar.xml;

import org.dellroad.sidekar.ArrayField;
import org.dellroad.sidekar.BigIntegerField;
import org.dellroad.sidekar.BooleanField;
import org.dellroad.sidekar.ByteField;
import org.dellroad.sidekar.CharacterField;
import org.dellroad.sidekar.DateField;
import org.dellroad.sidekar.DoubleField;
import org.dellroad.sidekar.Field;
import org.dellroad.sidekar.FieldSwitchAdapter;
import org.dellroad.sidekar.FloatField;
import org.dellroad.sidekar.IntegerField;
import org.dellroad.sidekar.Item;
import org.dellroad.sidekar.LongField;
import org.dellroad.sidekar.ReferenceField;
import org.dellroad.sidekar.ShortField;
import org.dellroad.sidekar.SimpleField;
import org.dellroad.sidekar.StringField;

/**
 * Wraps a {@link SimpleField}'s value in an {@link XMLField} object.
 * This class is used during marshalling.
 */
class XMLSimpleFieldSwitch extends FieldSwitchAdapter {

    protected final Item<?> item;

    protected XMLField xmlField;

    private Object value;

    /**
     * Constructor used for the "anonymous" values contained in complex fields.
     */
    public XMLSimpleFieldSwitch(Object value) {
        this.value = value;
        this.item = null;
    }

    /**
     * Constructor used for fields in an {@link Item}.
     */
    public XMLSimpleFieldSwitch(Item<?> item) {
        assert item != null;
        this.item = item;
    }

    /**
     * Get the {@link XMLField} created during the previous "visit".
     */
    public XMLSimpleField<?> getXMLSimpleField() {
        return (XMLSimpleField<?>)this.xmlField;
    }

    @Override
    public <E> void caseArrayField(ArrayField<E> field) {
        if (field.getElementField() instanceof ByteField)
            this.xmlField = new XMLByteArrayField(field.getName(), (byte[])getValue(field));
        else
            this.xmlField = new XMLArrayField<E>(field, getValue(field));
    }

    @Override
    public <T> void caseReferenceField(ReferenceField<T> field) {
        this.xmlField = new XMLReferenceField<T>(field.getName(), getValue(field));
    }

    @Override
    public void caseStringField(StringField field) {
        this.xmlField = new XMLStringField(field.getName(), getValue(field));
    }

    @Override
    public void caseDateField(DateField field) {
        this.xmlField = new XMLDateField(field.getName(), getValue(field));
    }

    @Override
    public void caseBigIntegerField(BigIntegerField field) {
        this.xmlField = new XMLBigIntegerField(field.getName(), getValue(field));
    }

    @Override
    public void caseBooleanField(BooleanField field) {
        this.xmlField = new XMLBooleanField(field.getName(), getValue(field));
    }

    @Override
    public void caseByteField(ByteField field) {
        this.xmlField = new XMLByteField(field.getName(), getValue(field));
    }

    @Override
    public void caseCharacterField(CharacterField field) {
        this.xmlField = new XMLCharacterField(field.getName(), getValue(field));
    }

    @Override
    public void caseShortField(ShortField field) {
        this.xmlField = new XMLShortField(field.getName(), getValue(field));
    }

    @Override
    public void caseIntegerField(IntegerField field) {
        this.xmlField = new XMLIntegerField(field.getName(), getValue(field));
    }

    @Override
    public void caseFloatField(FloatField field) {
        this.xmlField = new XMLFloatField(field.getName(), getValue(field));
    }

    @Override
    public void caseDoubleField(DoubleField field) {
        this.xmlField = new XMLDoubleField(field.getName(), getValue(field));
    }

    @Override
    public void caseLongField(LongField field) {
        this.xmlField = new XMLLongField(field.getName(), getValue(field));
    }

    @Override
    protected <T> void caseDefault(Field<T> field) {
        throw new RuntimeException("unexpected field: " + field);
    }

    /**
     * Get the value, either by extracting it from the {@link Item} or using the value provided to the constructor.
     */
    protected <E> E getValue(SimpleField<E> field) {
        if (this.item != null)
            return field.get(this.item);
        return field.cast(this.value);
    }
}

